import 'dart:math';

import 'package:flutter/material.dart';
import 'package:simple_animations/animation_builder/loop_animation_builder.dart';
import 'package:simple_animations/movie_tween/movie_tween.dart';
import 'package:supercharged/supercharged.dart';

///
/// 粒子动画
///
/// 1.粒子动画数据
/// 2.动画- customPaint
/// 3.循环动画
///
class ParticlesWidget extends StatefulWidget {
  final int numberOfParticles;

  ParticlesWidget(this.numberOfParticles, {super.key});

  @override
  State<StatefulWidget> createState() => _ParticlesWidgetState();
}

class _ParticlesWidgetState extends State<ParticlesWidget>
    with WidgetsBindingObserver {
  Random random = Random();
  List<ParticlesModel> particles = [];

  @override
  void initState() {
    super.initState();
    widget.numberOfParticles.times(
        () => particles.add(ParticlesModel(random))); //times() 是int类型的扩展方法
    WidgetsBinding.instance.addObserver(this); //监听生命周期变化
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  _simulateParticles() {
    particles
        .forEach((particle) => particle.checkIfParticleNeedsToBeRestarted());
  }

  @override
  Widget build(BuildContext context) {
    return LoopAnimationBuilder(
      tween: ConstantTween(1000),//这个对粒子没影响，没有用到值
      duration: const Duration(milliseconds: 100),//为0气泡展示一次就结束了，其他时间看不出明显变化
      builder: (context, child, dynamic _) {
        _simulateParticles();
        return CustomPaint(
          painter: ParticlePainter(particles),
        );
      },
    );
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    super.didChangeAppLifecycleState(state);
    if (state == AppLifecycleState.resumed) {
      //页面重新可见时，重置动画
      for (var value in particles) {
        value.restart();
        value.shuffle();
      }
    }
  }
}

class ParticlePainter extends CustomPainter {
  List<ParticlesModel> particles;

  ParticlePainter(this.particles);

  Random random = Random();

  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()..color = Colors.white.withAlpha(50);
    for (var element in particles) {
      final progress = element.progress();
      final Movie animation =
          element.tween.transform(progress); //补间动画根据progress获取对应帧

      final position = Offset(
          animation.get<double>(ParticlesOffsetProps.x) * size.width,
          animation.get<double>(ParticlesOffsetProps.y) * size.height); //粒子位置

      final radius = size.width * 0.2 * element.size; //粒子半径
      canvas.drawCircle(position, radius, paint);
    }
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
}

enum ParticlesOffsetProps { x, y }

class ParticlesModel {
  late MovieTween tween; //simple_animations库中动画所用补间动画数据模型
  Random random;
  late Duration duration; //粒子动画由开始到结束的执行时长
  late Duration startTime;
  late double size; //用于计算粒子半径，因为粒子的大小也是要随机生成

  ParticlesModel(this.random) {
    restart();
  }

  ///设定气泡位置、动画时间
  restart() {
    final startPosition =
        Offset(-0.2 + 1.4 * random.nextDouble(), 1.2); //初始位置，气泡从屏幕底部向顶部飘
    final endPosition = Offset(-0.2 + 1.4 * random.nextDouble(), -0.2); //结束位置

    tween = MovieTween()
      ..tween(
          ParticlesOffsetProps.x, //第一个参数是自定义的属性，可以是任意Object类型数据
          Tween(begin: startPosition.dx, end: endPosition.dx),
          duration: 2.seconds) //这个duration是啥意思
      ..tween(ParticlesOffsetProps.y,
          Tween(begin: startPosition.dy, end: endPosition.dy),
          duration: 2.seconds);

    duration = 3000.milliseconds + random.nextInt(6000).milliseconds;
    startTime = DateTime.now().duration();
    size = 0.2 + random.nextDouble() * 0.4; //random.nextDouble() ：[0.0,1.0)
  }

  ///重新设定起始时间，让粒子从新开始播放
  void shuffle() {
    startTime -= (random.nextDouble() *
            duration
                .inMilliseconds) //duration.inMilliseconds 是毫秒单位的 duration总时长
        .round() //取整
        .milliseconds; //创建毫秒单位的Duration对象
  }

  ///检查动画执行是否完成，如果已完成那么重新开始
  checkIfParticleNeedsToBeRestarted() {
    if (progress() == 1.0) {
      restart();
    }
  }

  ///在customPaint 绘制粒子所在位置时使用
  double progress() {
    //返回粒子运行时长比值
    return ((DateTime.now().duration() - startTime) / duration)
        .clamp(0.0, 1.0) //这个是在 0.0-1.0 之间取值，如果小于0.0，按0.0算 大于1.0 按1.0算
        .toDouble();
  }
}
